package com.yozi;

import android.app.*;
import android.widget.*;
import android.os.*;

import android.graphics.*;
import android.content.*;

import java.io.*;
import java.nio.*;


import android.util.*;
import android.content.res.Resources;

import android.view.*;
import android.view.ViewGroup.LayoutParams;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;

import com.yozi.*;
import com.swampex.*;

import android.hardware.SensorListener;
import android.hardware.SensorManager;

import android.location.*;

import java.util.List;
import android.content.Intent;

import android.os.PowerManager;
import java.text.DecimalFormat;

import 	android.os.SystemClock;
import 	android.view.animation.*;
import android.view.animation.Animation.AnimationListener;

import android.widget.Toast;

import com.robert.maps.kml.PoiActivity;
import com.robert.maps.kml.PoiListActivity;
import com.robert.maps.kml.PoiViewActivity;
import com.robert.maps.kml.PoiManager;
import com.robert.maps.kml.PoiPoint;
import com.robert.maps.kml.Track;
import com.robert.maps.kml.TrackListActivity;
import com.robert.maps.utils.Ut;

import com.robert.maps.utils.NinePatch;
import com.robert.maps.utils.NinePatchDrawable;

import org.andnav.osm.util.GeoPoint;
import android.graphics.Paint.Style;

import android.graphics.DashPathEffect;


public class TopoView extends View 
{
	int selectedPointID = -1;
	private float mBearing = 0;
	private NinePatchDrawable mButton = null;
	protected List<PoiPoint> mItemList;
	private PoiListThread mThread;

	int pen_x, pen_y, deltaX, deltaY;

	int markerPinOffset = 25;
	Paint mLinePaint = null;

	private Bitmap fillerSurface	= null;	
	private Bitmap movingCursor	= null;	
	private Bitmap standingCursor	= null;	
	private Bitmap poiSelectedSurface		= null;
	private Bitmap poiDefaultSurface		= null;

	int surface_dx = 0;
	int surface_dy = 0;
	private boolean mAutoFollow = true;
	private PoiManager mPoiManager = null;


	private int[] mapSurface		= null;

	boolean drawCursor = true;
	final Handler mHandler = new Handler();

	// Create runnable for posting
    final Runnable mUpdateResults = new Runnable() 
    {
        public void run() 
        {
            updateView();
        }
    };

	private final void updateView()
	{
		invalidate();
		//updateTitle();
	}


   	public void setDrawCursor(boolean draw)
   	{
   		drawCursor = draw;
   	}

   	public void setPoiManager(PoiManager manager)
   	{
   		mPoiManager = manager;
   		updatePoi();
   	}
   
   	public void setSurface(int[] surface)
   	{
   		mapSurface = surface;
   	}

   	private class PoiListThread extends Thread 
   	{
   		private double mdeltaX;
   		private double mdeltaY;

   		public void setParams(double deltaX, double deltaY)
   		{
   			mdeltaX = deltaX;
   			mdeltaY = deltaY;
   		}

   		@Override
   		public void run() 
   		{
   			mItemList = mPoiManager.getPoiList();

   			super.run();
   		}

   	}

   	public void initialize(int dx, int dy)
   	{
   	    surface_dx = dx;
       	surface_dy = dy;

   		Bitmap mBubbleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.popup_button);
   		byte[] chunk = {8,8,31,28}; // left,top,right,bottom
   		mButton = new NinePatchDrawable(new NinePatch(mBubbleBitmap, chunk, ""));

   		mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
   	    mLinePaint.setColor(0xF0FF0000);
       	mLinePaint.setStrokeWidth(3);
       	mLinePaint.setStyle(Style.STROKE);

   		DashPathEffect dashPath =
   			new DashPathEffect(new float[]{20,5, 3, 5}, 1);

   		mLinePaint.setPathEffect(dashPath);

		fillerSurface = 
           	BitmapFactory.decodeResource(getResources(), R.drawable.undermap);

		movingCursor = 
           	BitmapFactory.decodeResource(getResources(), R.drawable.arrow);

   		standingCursor =
           	BitmapFactory.decodeResource(getResources(), R.drawable.crossing);

   		poiSelectedSurface = 
           	BitmapFactory.decodeResource(getResources(), R.drawable.marker_red);

   		poiDefaultSurface = 
           	BitmapFactory.decodeResource(getResources(), R.drawable.marker_green);

		mThread = new PoiListThread();
   	}
   	

/*----------------------------------------------------------------------------*/
	public TopoView(Context context) 
   	{
		super(context);
	}

	public TopoView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
	}

   	public int getSelectedPointID()
   	{
   		return selectedPointID;
   	}

   	public void setSelectedPointID(int id)
   	{
   		selectedPointID = id;
   	}

   	public void setBearing(float bearing)
   	{
   		mBearing = bearing;
   	}

	void updatePoi()
   	{
   		mThread.run();
   	}

	void poiChanged()
   	{
   		mItemList = null;
   	}

   	public void setAutoFollow(boolean autoFollow) 
   	{
   		mAutoFollow = autoFollow;
   		update();

   		if (autoFollow)
   			Toast.makeText(getContext(), /*R.string.auto_follow_enabled*/ "Autofollow enabled", Toast.LENGTH_SHORT).show();
   		else
   			Toast.makeText(getContext(), /*R.string.auto_follow_disabled*/ "Autofollow disabled", Toast.LENGTH_SHORT).show();
   	}

   	public boolean getAutoFollow()
   	{
   		return mAutoFollow;
   	}

   	private boolean waypointTapped(int x, int y)
   	{
   	    if (selectedPointID != -1)
   		{
   			final Rect bounds = mButton.getBounds();

   			if (bounds.contains(x, y))
   			{
   				this.showContextMenu();					
   				return true;
   			}
   		}
   		

   		if (mItemList != null) 
   		{
   			for (int i = mItemList.size() - 1; i >= 0; i--) 
   			{
   				PoiPoint item = mItemList.get(i);

   				double lat = item.GeoPoint.getLatitude();
   				double lon = item.GeoPoint.getLongitude();

   				int point_x, point_y, center_x, center_y;

   				point_x = Swampex.getXbyLatLon(lat, lon);
   				point_y = Swampex.getYbyLatLon(lat, lon);

   				lat = Swampex.getLocationLat();
   				lon = Swampex.getLocationLon();

   				center_x = Swampex.getXbyLatLon(lat, lon);
   				center_y = Swampex.getYbyLatLon(lat, lon);

                  	int visible_x = point_x - center_x + surface_dx/2;
                   int visible_y = point_y - center_y + surface_dy/2;

   				final Rect pointBounds = new Rect();

   				int left = visible_x - markerPinOffset;
   				int right = visible_x + poiSelectedSurface.getWidth() - markerPinOffset;

   				int top = visible_y - poiSelectedSurface.getHeight();
   				int bottom = visible_y; 

   				pointBounds.set(left, top, right, bottom);

   				if(pointBounds.contains(x, y))
   				{
   					if (item.getId() == selectedPointID)
   						selectedPointID = -1;
   					else
   						selectedPointID = item.getId();

   					return true;
   				}
   			}
   		}

   		return false;
   	}

   /*----------------------------------------------------------------------------*/
   	@Override 
   	public boolean onTouchEvent(MotionEvent event) 
   	{
   		int action = event.getAction();
   		
   		
   		if (action == MotionEvent.ACTION_DOWN)
   		{
   			if (mAutoFollow == true)
   			{
   				setAutoFollow(false); 
   			}

   			pen_x = (int)event.getX();
   			pen_y = (int)event.getY();
   		}
   		else
   		if (action == MotionEvent.ACTION_MOVE)
   		{
   			int x = (int)event.getX();
   			int y = (int)event.getY();
   					
   			deltaX = -(pen_x - x);
   			deltaY = -(pen_y - y);

   			if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5)
   			{
   				this.invalidate();
   			}
   		}                                                                 	
   		else
   		if (action == MotionEvent.ACTION_UP)
   		{
   			int x = (int)event.getX();
   			int y = (int)event.getY();

   			deltaX = -(pen_x - x);
   			deltaY = -(pen_y - y);

   			if(	waypointTapped(pen_x, pen_y) || 
   				(Math.abs(deltaX) < 5 &&
   				 Math.abs(deltaY) < 5))
   			{
   				deltaX = 0;
   				deltaY = 0;
   				this.invalidate();
   			}
       		else 		
        		onDragFinished();
   		}

   		return true;
   	}

	public void update()
	{
		mHandler.post(mUpdateResults);
	}

	private final void onDragFinished()
	{
		Thread t = new Thread() 
		{
            public void run() 
            {
				Swampex.scrollMap(-deltaX, -deltaY);
			
				deltaX = 0;
				deltaY = 0;
			
                mapSurface = Swampex.getMapSurface();
                mHandler.post(mUpdateResults);
            }
        };
        t.start();	
    }

/*----------------------------------------------------------------------------*/
    @Override protected void onDraw(Canvas canvas) 
	{
		PoiPoint focusedItem = null;

//		canvas.drawRGB(0xFF, 0xFF, 0xFF);
		canvas.drawRGB(0, 0, 0);

        int w = canvas.getWidth();
        int h = canvas.getHeight();
        int cx = w / 2;
        int cy = h / 2;

        int centerX = -surface_dx/2;
        int centerY = -surface_dy/2;

        canvas.translate(cx, cy);

        canvas.drawBitmap(mapSurface, 0, surface_dx,  centerX + deltaX, centerY + deltaY, surface_dx, surface_dy, true, null);
		canvas.save();

		if (drawCursor == true && deltaX == 0 && deltaX == 0)
		{
			if (mAutoFollow == true)
			{
				canvas.rotate(mBearing, 0, 0);
				canvas.drawBitmap(movingCursor, -movingCursor.getWidth() / 2, -movingCursor.getHeight() / 2, null);
			}
			else
			{
				canvas.drawBitmap(standingCursor, -standingCursor.getWidth() / 2, -standingCursor.getHeight() / 2, null);
			}
		}

		canvas.restore();
		canvas.save();

		if (mItemList == null)
			updatePoi();


		if (mItemList != null && drawCursor == true && deltaX == 0 && deltaX == 0) 
		{
			for (int i = mItemList.size() - 1; i >= 0; i--) 
			{
				PoiPoint item = mItemList.get(i);

				double lat = item.GeoPoint.getLatitude();
				double lon = item.GeoPoint.getLongitude();

				int point_x, point_y, center_x, center_y;

				point_x = Swampex.getXbyLatLon(lat, lon);
				point_y = Swampex.getYbyLatLon(lat, lon);

				lat = Swampex.getLocationLat();
				lon = Swampex.getLocationLon();

				center_x = Swampex.getXbyLatLon(lat, lon);
				center_y = Swampex.getYbyLatLon(lat, lon);

               	int visible_x = point_x - center_x;
                int visible_y = point_y - center_y;


				if (item.getId() == selectedPointID)
				{
					focusedItem = item;

					canvas.drawLine(0, 0, visible_x, visible_y, mLinePaint);

    				canvas.drawBitmap(poiSelectedSurface, visible_x - markerPinOffset, //poiSelectedSurface.getWidth() / 2, 
    									visible_y - poiSelectedSurface.getHeight(), null);
				}
				else
    				canvas.drawBitmap(poiDefaultSurface, visible_x - markerPinOffset, //poiDefaultSurface.getWidth() / 2, 
    									visible_y - poiDefaultSurface.getHeight(), null);
			}
		}



		canvas.restore();
        canvas.translate(-cx, -cy);

        if (focusedItem != null)
		{
			double lat = Swampex.getLocationLat();
			double lon = Swampex.getLocationLon();

   			Canvas c = canvas;

   			int buttonPadding = 5;
   			
   			int canvasWidth = c.getWidth();

   			int textPadding = 4;

   			final int buttonWidth  = canvasWidth - buttonPadding*2;

   			Ut.TextWriter twTitle = new Ut.TextWriter(buttonWidth - textPadding, 16, focusedItem.Title);
   			
   			String distance = "?";

			GeoPoint center = new GeoPoint((int)(lat * 1E6), (int)(lon * 1E6));

   			float meters = focusedItem.GeoPoint.distanceTo(center);
   				
   			if (meters < 1000)
   				distance = meters + " m";
   			else
   				distance = meters/1000 + " km";
   			
   			Ut.TextWriter twDist  = new Ut.TextWriter(buttonWidth - textPadding, 14, distance);
   			Ut.TextWriter twCoord = new Ut.TextWriter(buttonWidth - textPadding, 12, Ut.formatGeoPoint(focusedItem.GeoPoint));

   			final int buttonHeight = 10 + twTitle.getHeight() + twDist.getHeight() + twCoord.getHeight() + 3*textPadding;

   			mButton.setBounds(buttonPadding, buttonPadding, buttonPadding + buttonWidth,
   					buttonHeight + buttonPadding);
   			mButton.draw(c);       	

   			twTitle.Draw(c, buttonPadding + textPadding, buttonPadding + textPadding);
   			twDist.Draw(c, buttonPadding + textPadding, twTitle.getHeight() + buttonPadding + textPadding*2);
   			twCoord.Draw(c, buttonPadding + textPadding, twTitle.getHeight() + twDist.getHeight() +  buttonPadding + 3*textPadding);

			focusedItem = null;
		}
		
    }
}
